#ifndef MYCOMPONENT_H
#define MYCOMPONENT_H

#include <QListWidgetItem>
#include <QTableWidgetItem>
#include <QVariant>
#include <QHash>
#include <QDebug>
#include <QTime>
#include <QRandomGenerator>

#include "FileAnalysis.h"

#define Song MusicFileInfo

template<typename T>
class ListNode
{
public:
    ListNode() : data(nullptr), pre(nullptr), next(nullptr){};
    ListNode(T dat, ListNode<T>* l1) : data(dat), pre(l1), next(nullptr){};
    ListNode(T dat, ListNode<T>* l1, ListNode<T>* l2) : data(dat), pre(l1), next(l2) {};
    ~ListNode(){delete data;}

public:
    ListNode<T>* pre;
    ListNode<T>* next;
    T data;
};

template<typename T>
class MyList
{
public:
    MyList():dump(){dump = new ListNode<T>(nullptr, nullptr, nullptr); tail = dump;}
    ~MyList();

    int size(){return cnt;};
    bool deleteNode(T item);
    bool addNode(T song);
    bool findNode(T node);
    ListNode<T>* start() {return dump->next;};
    ListNode<T>* getNode(T node);

private:
    QHash<T, ListNode<T>*> node_hash;
    ListNode<T>* dump;
    ListNode<T>* tail;
    ListNode<T>* cur;
    int cnt = 0;
};

template<typename T>
bool MyList<T>::deleteNode(T item)
{
    if(node_hash.find(item) != node_hash.end())
    {
        ListNode<T>* tmp = node_hash[item];
        tmp->pre->next = tmp->next;

        if(tail == tmp)
            tail = tmp->pre;
        else
            tmp->next->pre = tmp->pre;

        cnt--;
        node_hash.remove(item);
        delete tmp;

        return true;
    }

    return true;
}

template<typename T>
bool MyList<T>::addNode(T item)
{
    if(node_hash.find(item) != node_hash.end())
    {
        return false;
    }
    else
    {
        tail->next = new ListNode<T>(item, tail);
        tail = tail->next;
        node_hash.insert(item, tail);

        cnt++;
        return true;
    }
}

template<typename T>
bool MyList<T>::findNode(T node)
{
    if(node_hash.find(node) != node_hash.end())
        return true;
    else
        return false;
}

template<typename T>
ListNode<T>* MyList<T>::getNode(T node)
{
    if(node_hash.find(node) != node_hash.end())
    {
        return node_hash[node];
    }

    return nullptr;
}

//class Song
//{
//public:
//    Song(){};

//    QString path;
//    QString name;
//    QString album;
//    QString singer;
//    QString times;
//};

template<>
class MyList<Song*>
{
public:
    MyList()
    {
        dump = new ListNode<Song*>(nullptr, nullptr, nullptr);
        tail = dump;
    }
    ~MyList()
    {
        cur = dump;
        ListNode<Song*>* next;

        while(cur != NULL)
        {
            next = cur->next;
            delete cur;
            cur = next;
        }
    };

private:
    QHash<Song*, ListNode<Song*>*> node_hash;
    ListNode<Song*>* dump;
    ListNode<Song*>* tail;
    ListNode<Song*>* cur;
    int cnt = 0;

public:
    int size(){return cnt;};
    bool deleteNode(Song* item);
    bool addNode(Song* song);
    ListNode<Song*>* start() {return dump->next;};
    ListNode<Song*>* head() {return dump;};
    ListNode<Song*>* getNode(Song* song);
};

inline bool MyList<Song *>::deleteNode(Song *item)
{
    if(node_hash.find(item) != node_hash.end())
    {
        ListNode<Song*>* tmp = node_hash[item];
        tmp->pre->next = tmp->next;

        if(tail == tmp)
            tail = tmp->pre;
        else
            tmp->next->pre = tmp->pre;

        cnt--;
        node_hash.remove(item);
        delete tmp;

        return true;
    }

    return true;
}

inline bool MyList<Song*>::addNode(Song* item)
{
    qDebug() << "addNode";
    if(node_hash.find(item) != node_hash.end())
    {
        return false;
    }
    else
    {
        tail->next = new ListNode<Song*>(item, tail);
        tail = tail->next;
        node_hash.insert(item, tail);

        cnt++;
        return true;
    }
}

inline ListNode<Song*>* MyList<Song*>::getNode(Song* song)
{
    if(node_hash.find(song) != node_hash.end())
    {
        return node_hash[song];
    }

    return nullptr;
}


class MusicList : private MyList<Song*>
{
public:
    MusicList(){isFlush = false;};
    MusicList(int num, QString name, QString des): id(num), musiclist_name(name), description(des){isFlush = false;};

    bool addSong(Song* song){return addNode(song);};
    bool deleteSong(Song* song){return deleteNode(song);};
    int getSongCnt(){return MyList<Song*>::size();};

    bool clear()
    {
        ListNode<Song*>* cur = start();
        ListNode<Song*>* next;
        while(cur!= NULL)
        {
            next = cur->next;
            deleteNode(cur->data);
            cur = next;
        }

        return true;
    }

    void goStart()
    {
        cur_song = MyList<Song*>::head();
    };

    Song* Start()
    {
        cur_song = MyList<Song*>::start();
        if(cur_song != nullptr)
        {
            return cur_song->data;
        }

        return nullptr;
    };

    Song* next()
    {
        if(cur_song != nullptr && cur_song->next != nullptr)
        {
            cur_song = cur_song->next;
            return cur_song->data;
        }

        return nullptr;
    };

    Song* pre()
    {
        if(cur_song != nullptr && cur_song->pre != MyList<Song*>::head())
        {
            cur_song = cur_song->pre;
            return cur_song->data;
        }

        return nullptr;
    }

    bool setCurSong(Song* song)
    {
        ListNode<Song*>* tmp = MyList<Song*>::getNode(song);
        if(tmp)
        {
            cur_song = tmp;
            return true;
        }

        cur_song = MyList<Song*>::start();
        return false;
    }

public:
    int id;
    bool isFlush;
    ListNode<Song*>* cur_song;

    QString musiclist_name;
    QString description;
};

class LWI_MusicListItem : public QListWidgetItem
{
public:
    LWI_MusicListItem();
    LWI_MusicListItem(MusicList* ml) : m_musiclist(ml) {};
    LWI_MusicListItem(MusicList* ml, QIcon q) : m_musiclist(ml), QListWidgetItem(q, "") {};

    MusicList* getMusicList() {return m_musiclist;};

private:
    MusicList* m_musiclist;
};


class TWI_SongItem : public QTableWidgetItem
{
public:
    TWI_SongItem();
    TWI_SongItem(Song* s) : m_song(s) {};

    Song* getSong() {return m_song;};
private:
    Song* m_song;
};


class PlayList
{
public:
    enum PlayMode {SinglePlay, OrderPlay, LoopPlay, RandomPlay};

public:
    PlayList(PlayMode m) : mode(m), cur(0), size(0)
    {
        dump = new ListNode<Song*>();
        dump->next = dump;
        dump->pre = dump;
        cur_node = dump;
    };

    void setPlayMode(PlayMode m) {mode = m;}
    PlayMode getPlayMode(){return mode;}

    Song* playNext();
    Song* playPre();
    Song* play();   //当前歌曲播放完毕时的动作
    bool setCurSong(Song*);
    bool addNextSong(Song* s, bool isNew);        //下一首播放
    bool Random(int start, int end);  //随机歌曲顺序
    bool deleteSong(Song* s);         //删除歌曲
    bool addSong(Song* s);            //添加歌曲到最后
    bool addMusiclist(MusicList* ml);
    ListNode<Song*>* getDump() {return dump;};
    int getSize() {return size;};
    void clear();
    void swap(int pos1, int pos2);

private:
    PlayMode mode;
    QVector<Song*> vec;        //随机播放列表
    QHash<Song*, QPair<int, ListNode<Song*>*>> song_hash;
    ListNode<Song*>* dump;                //环状链表，初始顺序

    int cur;
    int order;
    int size;
    ListNode<Song*>* cur_node;

};

Q_DECLARE_METATYPE(Song*)
Q_DECLARE_METATYPE(MusicList*)

#endif // MYCOMPONENT_H
